package com.jysz.certificate.service.mf;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;

import com.jysz.certificate.persistence.dao.mf.BillDao;
import com.jysz.certificate.persistence.dao.mf.BillOptionDao;
import com.jysz.certificate.persistence.dao.system.FinancialDao;
import com.jysz.certificate.persistence.enums.PostType;
import com.jysz.certificate.persistence.enums.mf.BillStatus;
import com.jysz.certificate.persistence.model.mf.Bill;
import com.jysz.certificate.persistence.model.mf.BillOption;
import com.jysz.certificate.persistence.model.system.Shop;
import com.jysz.certificate.persistence.model.system.Treaty;
import com.jysz.certificate.persistence.model.system.User;
import com.jysz.certificate.service.system.TreatyService;
import com.jysz.certificate.utils.CommonUtil;
import com.jysz.certificate.utils.DateUtil;
import com.jysz.webcore.ssh.orm.hibernate.support.Page;
import com.jysz.webcore.ssh.service.EntityService;

/**
 * 发票Service
 * @author xuxiaolong
 */
@Service
public class BillService extends EntityService<Bill, Long, BillDao> {

	@Override
	public BillDao getEntityDao() {
		return this.billDao;
	}

	@Resource
	private BillDao billDao;
	@Resource
	private BillOptionDao optionDao;
	@Resource
	private FinancialDao financialDao;
	@Resource
	private TreatyService treatyService;
	
	
	/**
	 * 发票修改
	 * @author xuxiaolong
	 * @param billId
	 * @param editData修改的记录
	 * @param newData 新增的记录
	 */
	public Bill update(Long billId,String editData,String newData){
		Bill bill=super.find(billId);
		Double sum=0D,tmp=0D;
		if(CommonUtil.isNotEmpty(editData)){
			String editAry[]=editData.split(",");
			//已存在编辑
			for(String edit:editAry){
				if(CommonUtil.isNotEmpty(edit)){
					String row[]=edit.split("_");
					BillOption option= optionDao.find(Long.parseLong(row[0]));
					tmp=Double.parseDouble(row[1]);
					sum+=tmp-option.getAmount();
					option.setAmount(tmp);
					if(row.length==3)
						option.setRemark(row[2]);
					if(tmp<option.getAmount())
						option.setLessThan(1);
					else
						option.setLessThan(0);
					optionDao.save(option);
				}
			}
			
		}
		//新增
		if(CommonUtil.isNotEmpty(newData)){
			String newAry[]=newData.split(",");
			for(String create:newAry){
				if(CommonUtil.isNotEmpty(create)){
					String row[]=create.split("_");
					BillOption option=new BillOption();
					option.setBillsForOne(bill);
					option.setFinancial(financialDao.find(Long.parseLong(row[0])));
					option.setShop(bill.getShop());
					
					tmp=Double.parseDouble(row[1]);
					sum+=tmp;
					option.setAmount(tmp);
					Treaty treaty=treatyService.find(option.getFinancial().getId(),option.getShop().getId());
					if(tmp<treaty.getFloors())
						option.setLessThan(1);
					else
						option.setLessThan(0);
					option.setMonth(row[2]);
					option.setAdvance(true);
					option.setOperate(0);
					option.setStatus(BillStatus.TEMPSAVE);
					option.setTreaty(treaty);//添加协议
					if(row.length==4)
						option.setRemark(row[3]);
					optionDao.save(option);
				}
			}
			
		}
		bill.setReceivableAmount(bill.getReceivableAmount()+sum);
		this.save(bill);
		return bill;
		
	}
	
	//仅用于季度、半年的新增预收
	public String addOptions(String group,Bill bill,Treaty treaty,String ...mons){
		Double sum=0D,tmp=0D;
		StringBuilder sb=new StringBuilder();
		//新增
		if(mons!=null){
			String mon;
			for(int i=0;i<mons.length;i++){
				mon=mons[i];
					BillOption option=new BillOption();
					option.setBillsForOne(bill);
					option.setFinancial(treaty.getFinancial());
					option.setShop(bill.getShop());
					option.setGroup(group);
					
					tmp=treaty.getFloors()!=null?treaty.getFloors():0D;
					sum+=tmp;
					option.setAmount(tmp);
					option.setLessThan(0);
					option.setMonth(mon);
					option.setAdvance(true);
					option.setOperate(0);
					option.setStatus(BillStatus.TEMPSAVE);
					option.setTreaty(treaty);//添加协议
					optionDao.save(option);
					if(i==mons.length-1)
						sb.append(mon).append("_").append(option.getId());
					else
						sb.append(mon).append("_").append(option.getId()).append(",");
			}
			
		}
		bill.setReceivableAmount(bill.getReceivableAmount()+sum);
		this.save(bill);
		return sb.toString();
		
	}
	
	
	public Page<Bill> findPage(Boolean bool,Bill bill ,int pageNo, int pageSize,Date openDateBegin,Date openDateEnd,Date applyDateBegin,Date applyDateEnd,Integer status,User user){
		Criteria criteria = billDao.createCriteria();
		if(user.getPost().equals(PostType.Manager)){
			criteria.addOrder(Order.desc("openDate"));
		}else{
			criteria.addOrder(Order.asc("status"));
		}
//		criteria.addOrder(Order.asc("status"));
		criteria.add(Restrictions.not(Restrictions.eq("status", BillStatus.TEMPSAVE)));//不需要将暂存状态显示出来
//		criteria.add(Restrictions.not(Restrictions.eq("status", BillStatus.APPLYED)));//不需要将已申请开票状态显示出来600
		if(null != bill){
			if(StringUtils.isNotBlank(bill.getBillNum())){
				criteria.add(Restrictions.like("billNum", bill.getBillNum(),MatchMode.START));
			}
			if(StringUtils.isNotBlank(bill.getBillName())){
				criteria.add(Restrictions.like("billName", bill.getBillName(),MatchMode.START));
			}
			if(StringUtils.isNotBlank(bill.getPaymentName())){
				criteria.add(Restrictions.like("paymentName", bill.getPaymentName(),MatchMode.START));
			}
			if(status != null && status>=0){
				criteria.add(Restrictions.eq("status",BillStatus.index(status)));
			}
			if(bill.getShop() != null ){
				criteria.add(Restrictions.eq("shop.id", bill.getShop().getId()));
			}
		}
		if(bool == false){
			criteria.add(Restrictions.gt("receivableAmount", 0D));
		}
		if(!user.getPost().equals(PostType.Responsible))
			billDao.addShopCriteria(criteria,false,null);//添加数据过滤
		if(null != openDateBegin){
			criteria.add(Restrictions.ge("openDate", openDateBegin));
		}
		if(null != openDateEnd){
			criteria.add(Restrictions.le("openDate", DateUtil.addDays(openDateEnd,1)));
		}
		if(null != applyDateBegin && null != applyDateEnd){
			criteria.createCriteria("billApply").add(Restrictions.between("applyDate", applyDateBegin, DateUtil.addDays(applyDateEnd,1)));
		}else{
			if(null != applyDateBegin){
				criteria.createCriteria("billApply").add(Restrictions.ge("applyDate", applyDateBegin));
			}
			if(null != applyDateEnd){
				criteria.createCriteria("billApply").add(Restrictions.le("applyDate", DateUtil.addDays(applyDateEnd,1)));
			}
		}
		
		return this.findPage(criteria, pageNo, pageSize);
		
	}
	
	public List<Bill> exportBills(Boolean bo,Bill bill ,int pageNo, int pageSize,Date openDateBegin,Date openDateEnd,Date applyDateBegin,Date applyDateEnd,Integer status){
		Criteria criteria = billDao.createCriteria();
		criteria.add(Restrictions.not(Restrictions.eq("status", BillStatus.TEMPSAVE)));//不需要将暂存状态显示出来
		criteria.addOrder(Order.desc("shop"));
		if(null != bill){
			if(StringUtils.isNotBlank(bill.getBillNum())){
				criteria.add(Restrictions.like("billNum", bill.getBillNum(),MatchMode.START));
			}
			if(StringUtils.isNotBlank(bill.getBillName())){
				criteria.add(Restrictions.like("billName", bill.getBillName(),MatchMode.START));
			}
			if(StringUtils.isNotBlank(bill.getPaymentName())){
				criteria.add(Restrictions.like("paymentName", bill.getPaymentName(),MatchMode.START));
			}
			if(status != null && status>=0){
				criteria.add(Restrictions.eq("status",BillStatus.index(status)));
			}
			if(bill.getShop() != null ){
				criteria.add(Restrictions.eq("shop.id", bill.getShop().getId()));
			}
		}
		if(bo == false){
			criteria.add(Restrictions.gt("receivableAmount", 0D));
		}
		billDao.addShopCriteria(criteria,false,null);//添加数据过滤
		if(null != openDateBegin){
			criteria.add(Restrictions.ge("openDate", openDateBegin));
		}
		if(null != openDateEnd){
			criteria.add(Restrictions.le("openDate", DateUtil.addDays(openDateEnd,1)));
		}
		if(null != applyDateBegin){
			criteria.createCriteria("billApply").add(Restrictions.ge("applyDate", applyDateBegin));
		}
		if(null != applyDateEnd){
			criteria.createCriteria("billApply").add(Restrictions.le("applyDate", DateUtil.addDays(applyDateEnd,1)));
		}
		
		
		return criteria.list();
		
	}
	public Bill minuteBill(String paymentName,Double receivableAmount,String billRemark){
		Criteria criteria =getEntityDao().createCriteria();
		criteria.add(Restrictions.eq("paymentName", paymentName));
		criteria.add(Restrictions.eq("receivableAmount", receivableAmount));
		criteria.add(Restrictions.eq("billRemark", billRemark));
		criteria.add(Restrictions.eq("status", BillStatus.APPLYED));
		List<Bill> bills = criteria.list();
		if(null != bills && bills.size()>0){
			return bills.get(0);
		}
		return null;
	}

	public void del(Bill bill){
		List<BillOption> options=bill.getOptions();
		if(options!=null){
			for(BillOption option:options){
				optionDao.destory(option);
			}
		}
		bill.setOptions(null);
		this.destory(bill);
		
	}
	/**
	 * 实收
	 * @author xuxiaolong
	 * @param billId 发票ID
	 * @param ids    明细ids
	 */
	public void income(Long billId,Long[]ids){
		Bill bill=this.find(billId);
		double count=0;
		if(bill.getFactAmount()!=null)
			count=bill.getFactAmount();
		BillOption option=null;
		for(Long id:ids){
			option=optionDao.find(id);
			option.setStatus(BillStatus.CHARGED);//已实收
			option.setIncomeDate(new Date());
			optionDao.save(option);
			count+=option.getAmount();
		}
		bill.setFactAmount(count);
		List<BillOption> options=bill.getOptions();
		boolean flag=true;
		for(BillOption bo:options){
			if(bo.getStatus().compareTo(BillStatus.CHARGED)!=0){
				flag=false;
				break;
			}
		}
		if(flag){
			bill.setStatus(BillStatus.FULLCHARGE);//完全实收
			bill.setIncomeDate(new Date());
			super.save(bill);
		}else if(bill.getStatus().compareTo(BillStatus.PARTCHARGE)!=0){
			bill.setStatus(BillStatus.PARTCHARGE);//部分实收
			super.save(bill);
		}
			
	}
	
	/**
	 * 注销
	 * @author xuxiaolong
	 * @param billId 发票ID
	 * @param ids    明细ids
	 */
	public void cancel(Long billId,Long[]ids,String billNum,String billName,Date openDate){
		BillOption option=null;
		List<BillOption> list=new ArrayList<BillOption>();
		Double amount=0D;
		for(Long id:ids){
			option=optionDao.find(id);
			option.setStatus(BillStatus.CANCELED);//已注销
			optionDao.save(option);
			list.add(option);
			amount+=option.getAmount();
		}
		Bill bill=this.find(billId);
		Bill newBill=new Bill(bill,billNum,billName,amount,BillStatus.REDFONT);
		newBill.setOpenDate(openDate);
		newBill.setOptions(list);
		this.buildBillRemark(newBill);//发票备注
		super.save(newBill);
		
		//检测旧发票，如果所有明细都为已注销，旧发票也改为已注销
		boolean needUpdate=true;
		for(BillOption bo:bill.getOptions()){
			if(bo.getStatus().compareTo(BillStatus.CANCELED)!=0){
				needUpdate=false;
				break;
			}
		}
		if(needUpdate){
			bill.setStatus(BillStatus.CANCELED)	;
			super.save(bill);
		}
	}
	
	/**
	 * 作废
	 * @param id 发票ID
	 */
	public void invalid(Long id){
		Bill bill=find(id);
		List<BillOption> options=bill.getOptions();
		for(BillOption bo:options){
			bo.setStatus(BillStatus.INVALID);//发票明细状态改为已作废
			optionDao.save(bo);
		}
		bill.setStatus(BillStatus.INVALID);
		super.save(bill);
	}
	
	/**
	 * 作废重开
	 * @param id 发票ID
	 */
	public void reopen(Long billId,Long ids[],Long uncheckIds[],boolean hasCharged,String billNum,String billName,Date openDate){
		BillOption option=null;
		List<BillOption> list=new ArrayList<BillOption>();
		Double amount=0D;
		for(Long id:ids){//选中的（包含已实收 ）
			option=optionDao.find(id);
			list.add(option);
			amount+=option.getAmount();
		}
		if(null != uncheckIds && uncheckIds.length>0){
			for(Long id:uncheckIds){//未选中的
				option=optionDao.find(id);
				option.setStatus(BillStatus.INVALID);//已作废
				optionDao.save(option);
			}	
		}
		
		Bill bill=this.find(billId);
		bill.setStatus(BillStatus.INVALID);//已作废
		super.save(bill);
		
		Bill newBill=new Bill(bill,billNum,billName,amount,hasCharged?BillStatus.PARTCHARGE:BillStatus.OPENED);
		newBill.setOptions(list);
		newBill.setOpenDate(openDate);
		this.buildBillRemark(newBill);//发票备注
		super.save(newBill);
	}
	
	/**
	 * 注销重开
	 * @param id 发票ID
	 */
	public void cancleReopen(Long billId,Long ids[],Long uncheckIds[],boolean hasCharged,String billNum,String billName,Date openDate){
		BillOption option=null;
		List<BillOption> list=new ArrayList<BillOption>();
		Double amount=0D;
		for(Long id:ids){//选中的（包含已实收 ）
			option=optionDao.find(id);
			list.add(option);
			amount+=option.getAmount();
		}
		if(null != uncheckIds && uncheckIds.length>0){
			for(Long id:uncheckIds){//未选中的
				option=optionDao.find(id);
				option.setStatus(BillStatus.CANCLEREDREOPEN);//注销重开
				optionDao.save(option);
			}	
		}
		
		Bill bill=this.find(billId);
		bill.setStatus(BillStatus.REDFONT);//注销 红字
		super.save(bill);
		
		Bill newBill=new Bill(bill,billNum,billName,amount,hasCharged?BillStatus.PARTCHARGE:BillStatus.OPENED);
		newBill.setOptions(list);
		newBill.setOpenDate(openDate);
		this.buildBillRemark(newBill);//发票备注
		super.save(newBill);
	}
	
	/**
	 * 未实收的发票 店铺
	 * @param shops  店铺Id
	 * @param fianlId  金融机构ID
	 * @return
	 */
	public Integer openBillAmount(Set<Shop> shops){
		Criteria criteria = billDao.createCriteria();
		criteria.setProjection(Projections.rowCount());
		
		if(null != shops && shops.size() > 0){
			criteria.add(Restrictions.in("shop", shops));
		}
		
		criteria.add(Restrictions.or(Restrictions.eq("status", BillStatus.OPENED), Restrictions.eq("status", BillStatus.PARTCHARGE)));
		criteria.add(Restrictions.gt("receivableAmount", 0.0D));
		return ((Number)criteria.uniqueResult()).intValue();
	}
	
	/**
	 * 未实收的发票 独立开票 金融机构
	 * @param shops  店铺Id
	 * @param fianlId  金融机构ID
	 * @return
	 */
	public Integer findOpenBillByFinancial(){
		
		Criteria criteria = billDao.createCriteria();
		criteria.setProjection(Projections.rowCount());
		criteria.add(Restrictions.eq("status", BillStatus.OPENED));
		criteria.createCriteria("financial").add(Restrictions.eq("billing", "0"));
		return ((Number)criteria.uniqueResult()).intValue();
	}
	
	/**
	 * 获得所有发票名
	 * @return
	 */
	public Map<String, Bill> billMapBillName(){
		Map<String, Bill> billMap = new HashMap<String, Bill>();
		Criteria criteria = billDao.createCriteria();
		criteria.add(Restrictions.isNotNull("billName"));
		List<Bill> bills = criteria.list();
		for(int i=0;i<bills.size();i++){
			Bill bill = bills.get(i);
			if(!billMap.containsKey(bill.getBillName())){
				billMap.put(bill.getBillName(), bill);
			}
		}
		return billMap;
	}
	/**
	 * 获得所有发票号
	 * @return
	 */
	public Map<String, Bill> billMapBillNum(){
		Map<String, Bill> billMap = new HashMap<String, Bill>();
		Criteria criteria = billDao.createCriteria();
		criteria.add(Restrictions.isNotNull("billNum"));
		List<Bill> bills = criteria.list();
		for(int i=0;i<bills.size();i++){
			Bill bill = bills.get(i);
			if(!billMap.containsKey(bill.getBillNum())){
				billMap.put(bill.getBillNum(), bill);
			}
		}
		return billMap;
	}
	
	public void buildBillRemark(Bill bill){
		List<BillOption>options=bill.getOptions();
		if(options!=null){
			Map<String,List<BillOption>> map=new HashMap<String, List<BillOption>>();
			for(BillOption option:options){
				if(bill.getStatus().compareTo(BillStatus.REDFONT)==0){
					option.setStatus(BillStatus.CANCELED);
				}else if(option.getStatus().getIndex()<bill.getStatus().getIndex()&&bill.getStatus().compareTo(BillStatus.PARTCHARGE)!=0&&bill.getStatus().compareTo(BillStatus.FULLCHARGE)!=0){
					option.setStatus(bill.getStatus());
				}
				if(map.containsKey(option.getFinancial().getName())){
					map.get(option.getFinancial().getName()).add(option);
				}else{
					List<BillOption> l=new ArrayList<BillOption>();
					l.add(option);
					map.put(option.getFinancial().getName(), l);
				}
			}
			//构建发票备注
			StringBuilder sb=new StringBuilder();
			for(String key:map.keySet()){
				sb.append(key).append(":");
				double d=0.0;
				for(BillOption tmp:map.get(key)){
					sb.append(getIntMonth(tmp.getMonth())).append("月 ");
					d+=tmp.getAmount();
				}
				sb.append(d).append(";");
			}
			bill.setBillRemark(sb.toString());
		}
	}
	//获得整数月份
		private static String getIntMonth(String month){
			if(CommonUtil.isNotEmpty(month)&&month.length()==7){
				String tmp=month.substring(5, 7);
				Integer m=Integer.parseInt(tmp);
				return m.toString();
			}
			return null;
		}
}
